
#include "buffermanager.hpp"

/*########################################################################################################

  Funcions de la classe bufferManager

  La clase bufferManager s'encarrega de gestionar les entrades i sortides al disc.

  ######################################################################################################*/


bufferManager::bufferManager(char* pPath)
{
    _file = fopen(pPath, "rb+");
    for (int i = 0; i < 32; i++)
    {
        _pool[i].data=new char[1024];
        _pool[i].pin=0;
        _pool[i].dirty=false;
        _pool[i].npag=-1;
    }
}


char* bufferManager::query(int pPag)
{

    char* pPunter = NULL;
    int n = -1;
    n = find(pPag);
    //Si la pagina és a memoria, apuntem a ella.
    if (n >= 0)
    {
        pPunter = _pool[n].data;
        _pool[n].pin++;

        //Si no és a memoria, busquem espai al pool per importar-la.
    }
    else
    {
        n = find();
        //Si hi ha espai, la posem
        if (n >= 0)
        {
            //Apuntem al inici de la pàgina, al disc.
            fseek (_file, (1024 * pPag), SEEK_SET);
            //Llegim pàgina del disc i la coloquem.
            int res = fread (_pool[n].data, 1, 1024, _file);
            if (res == 0) {fputs ("Error de lectura", stderr); exit (3);}
            pPunter = _pool[n].data;
            _pool[n].dirty = false;
            _pool[n].npag = pPag;
            //cout << pPag << endl;
            //Pinejem la pàgina.
            _pool[n].pin++;
            //Si no hi ha espai, error!
        }
        else
        {
            //cout << "ERROR: Cache plena!" << endl;
        }
    }
    return pPunter;
}


void bufferManager::update(int pPag)
{
    int n = -1;
    n = find(pPag);
    //Si la pagina és a memoria, la desem.
    if (n >= 0)
    {
        save(n);
        _pool[n].pin--;
    }
}

void bufferManager::unpin(int pPag)
{
    int n = find(pPag);
    if(n >= 0) _pool[n].pin--;
}


void bufferManager::stat(int pFrm)
{
    if (pFrm != 0)
    {
        cout << "[STAT frm " << pFrm << "] ";
        cout << "Pagina: " << _pool[pFrm].npag << " | ";
        cout << "PIN: " << _pool[pFrm].pin << " | ";
        cout << "dirty: " << _pool[pFrm].dirty << endl;
    }
    else
    {
        for (int i = 0; i < 32; i++)
        {
            cout << "[STAT frm " << i << "] ";
            cout << "Pagina: " << _pool[i].npag << " | ";
            cout << "PIN: " << _pool[i].pin << " | ";
            cout << "dirty: " << _pool[i].dirty << endl;
        }
    }
}


bufferManager::~bufferManager()
{
    empty();
    fclose(_file);
}


// FUNCIONS AUXILIARS /////////////////////////////////////////////////////////


int bufferManager::find()
{
    int n = -1;
    for(int i = 0; i<32 and n==-1; i++) //busquem verges
        if ( _pool[i].pin == 0 && _pool[i].dirty == false) n = i;
    if (n == -1)  //si no hi han...
        for(int i = 0; i<32 and n==-1; i++)  //busquem no-verges
        {
            if ( _pool[i].pin == 0 && _pool[i].dirty == true)
            {
                remove(i);
                n = i;
            }
        }
    return n;
}


int bufferManager::find(int pPag)
{
    int n = -1;
    for(int i = 0; i<32 and n==-1; i++)
        if (_pool[i].npag == pPag) n = i;
    return n;
}


void bufferManager::save(int pBuf)
{
    fseek (_file, (1024 * _pool[pBuf].npag), SEEK_SET);
    fwrite(_pool[pBuf].data, 1024, 1, _file);
    _pool[pBuf].dirty = false;
    //cout << "guardant" << pBuf << " a " << _pool[pBuf].npag << endl;
}


void bufferManager::remove(int pBuf)
{
    delete _pool[pBuf].data;
    _pool[pBuf].data = new char[1024];
    _pool[pBuf].npag = -1;
    _pool[pBuf].pin = 0;
    _pool[pBuf].dirty = false;
}


void bufferManager::empty()
{
    for (int i = 0; i < 32; i++)
        if (_pool[i].dirty)
        {
            save(i);
            remove(i);
        }
}

